#include "xmppFilter.h"
#include <string.h>


#define send_xmpp_msg(_parser,_from,properties, _msg) \
do {\
  iks *_reply = iks_make_msg(IKS_TYPE_CHAT,_from, (char *)_msg);\
  if( NULL != (iks*)properties ) iks_insert_node(_reply, (iks*)properties );\
  if( _reply ) {\
    iks_send(_parser, _reply);\
    iks_delete(_reply);\
  }\
} while(0)

xmppFilter::xmppFilter( baseCallbacks *cbs, xmppLogger *logger):
                        calls(cbs),log(logger)
{
  this->_filter = iks_filter_new();
}

xmppFilter::xmppFilter(const xmppFilter &rhs)
{
  this->calls = rhs.calls;
  this->_filter = rhs._filter;
  this->log = rhs.log;
}

xmppFilter::~xmppFilter()
{
  iks_filter_delete(this->_filter);
  this->calls = NULL;
  this->_filter = NULL;
}

xret
xmppFilter::setupFilter(iksparser *p)
{
  if( NULL == p ) return xp_FAIL;
  this->_parser = p;

  iks_filter_add_rule(this->_filter,
    (iksFilterHook *) xmppFilter::process_bind, this,
    IKS_RULE_TYPE, IKS_PAK_IQ,
    IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
    IKS_RULE_ID, XP_IQ_SESSION_ID,
    IKS_RULE_DONE);

  iks_filter_add_rule(this->_filter,
    (iksFilterHook *) xmppFilter::process_message, this,
    IKS_RULE_TYPE, IKS_PAK_MESSAGE,
    IKS_RULE_SUBTYPE, IKS_TYPE_CHAT,
    IKS_RULE_DONE);
/*
  HBL CommandList and AppInfo
*/
  iks_filter_add_rule(this->_filter,
    (iksFilterHook *) xmppFilter::process_presence, this,
    IKS_RULE_TYPE, IKS_PAK_PRESENCE,
    IKS_RULE_DONE);

  iks_filter_add_rule(this->_filter,
    (iksFilterHook *) xmppFilter::process_iq, this,
    IKS_RULE_TYPE, IKS_PAK_IQ,
    IKS_RULE_DONE);
  return xp_OK;
}

xret
xmppFilter::getFilter(iksfilter **rfilter)
{
  *rfilter = this->_filter;
  return xp_OK;
}

int
xmppFilter::process_message(void *_this, ikspak *pak)
{
  char *_msg = NULL;
  iks *body = NULL;
  char wdata[XP_XMPP_WRITE_BUF_MAX] = {0};
  size_t len = XP_XMPP_WRITE_BUF_MAX;
  xmppFilter *t = (xmppFilter *)_this;

  if( NULL == t )
    return IKS_FILTER_PASS;

  if( t->log )
    t->log->debug("%s","Message received");

  if( !(body=iks_find(pak->x,"body")) ) {
    if( t->log )
      t->log->warn("%s","no <body> element in the message discarding it.");
    app_debug("%s","No body in the message");
    return IKS_FILTER_EAT;
  }
  if( !(_msg=iks_cdata(iks_child(body))) ) {
    app_debug("%s","No CONTENT in body in the message");
    if( t->log )
      t->log->warn("%s","no content of body, discarding it");
    return IKS_FILTER_EAT;
  }
  if( t->log )
    t->log->debug("post message [%s]", _msg);
  app_debug("post message [%s]", _msg);
  if( xp_OK!=t->calls->handleMessage(pak->from->partial, _msg,
                                      wdata, &len)) {
    return IKS_FILTER_PASS;
  }
  if( strlen(wdata) == len && 0 < len ) {
    iks *properties = iks_find(pak->x, "properties");
    send_xmpp_msg(t->_parser,pak->from->full , properties,  wdata);
    if( t->log )
      t->log->debug("%s","Posting reply to the sender");
  }
  return IKS_FILTER_EAT;
}

int
xmppFilter::process_presence(void *_this, ikspak *pak)
{
  xmppFilter *t = (xmppFilter *)_this;
  if( NULL == t )
    return IKS_FILTER_PASS;

  if( xp_OK!=t->calls->handlePresence(t->_parser, pak)) {
    if( t->log )
      t->log->error("%s","handler Presence");
  }

  if( t->log )
    t->log->debug("%s","Presence received");
  return IKS_FILTER_EAT;
}

int
xmppFilter::process_bind(void *_this, ikspak *pak)
{
  iks *x = NULL;
  char statMsg[XP_XMPP_STAT_BUF_MAX] = {0};
  size_t len = XP_XMPP_STAT_BUF_MAX;

  xmppFilter *t = (xmppFilter *)_this;

  if( NULL == t )
    return IKS_FILTER_PASS;

  if( t->log )
    t->log->debug("%s","Auth Passed! Bind called.");

  if( xp_OK!=t->calls->handleBind(statMsg, &len)) {
    if( t->log )
      t->log->error("%s","handler failed to return BIND message");
    return IKS_FILTER_PASS;
  }

  if( strlen(statMsg) == len && 0 < len ) {
    x = iks_make_pres(IKS_SHOW_CHAT, statMsg );

    if( NULL == x )
      return IKS_FILTER_PASS;

    app_debug("Out len [%d] strlen(%d)", len, strlen(statMsg) );
    iks_send(t->_parser, x);
    iks_delete(x);
    x = NULL;
    if( t->log )
      t->log->debug("%s","Bind message sent");
  }
  x = iks_new ("iq");
  iks_insert_attrib (x, "type", "get");
  iks_insert_attrib (x, "id", XP_IQ_MUC_ID );
  iks_insert_attrib (iks_insert(x, "query" ),
                      "xmlns","http://jabber.org/protocol/disco#items");
  iks_send(t->_parser, x);
  iks_delete(x);
  if( t->log )
    t->log->debug("%s","MUC - IQ initiated");
  return IKS_FILTER_EAT;
}

int
xmppFilter::process_iq(void *_this, ikspak *pak)
{
  xmppFilter *t = (xmppFilter *)_this;
  if( NULL == t )
    return IKS_FILTER_PASS;

  if( t->log )
    t->log->debug("%s","IQ received.");
  if( xp_OK!=t->calls->handleIq(t->_parser,pak))
    return IKS_FILTER_PASS;
  return IKS_FILTER_EAT;
}

/*
vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=2:encoding=utf-8:textwidth=80
*/
